package com.cx.common.http;

import com.cx.common.utils.JsonUtils;
import com.cx.common.thread.ExecutorUtils;
import com.cx.common.thread.NamedThreadFactory;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.*;

/**
 * Http工具
 * 
 * @Author:cxy
 * @Date:2019/10/24 15:11
 */
public class HttpUtils {

	private static final Logger LOGGER = LoggerFactory.getLogger(HttpUtils.class);
	/** 请求方法 */
	public static String HTTP_METHOD_GET = "get";
	public static String HTTP_METHOD_POST = "post";

	/** 编码方式 */
	private static final String CONTENT_CHARSET = "UTF-8";

	/** 连接超时时间 */
	private int CONNECTION_TIMEOUT = 30000;

	/** 读数据超时时间 */
	private int READ_DATA_TIMEOUT = 30000;

	private static HttpClient httpClient;

	private static HttpUtils instance;

	NamedThreadFactory threadFactory = new NamedThreadFactory(new ThreadGroup("http请求"), "http请求");

	static {
		instance = new HttpUtils();
		getHttpClient();
	}

	private HttpUtils() {
	}

	/** 执行队列 */
	private ExecutorService pool = new ThreadPoolExecutor(1, 4, 30, TimeUnit.SECONDS,
			new LinkedBlockingQueue<Runnable>(), threadFactory);

	/**
	 * 提交请求任务
	 * 
	 * @param task
	 *            提交的任务事件
	 * @return {@link Future} 提交的任务句柄
	 */
	public static <T> Future<T> submit(Callable<T> task) {
		return instance.pool.submit(task);
	}

	public static Future<?> submit0(Runnable task) {
		return instance.pool.submit(task);
	}

	/**
	 * 取得HttpClient实例
	 * 
	 * @return {@link HttpClient}
	 */
	public static HttpClient getHttpClient() {
		if (httpClient == null) {
			synchronized (HttpUtils.class) {
				if (httpClient == null) {
					int max = Runtime.getRuntime().availableProcessors() + 1;
					HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
					HttpConnectionManagerParams params = connectionManager.getParams();
					params.setMaxTotalConnections(max + 1);
					params.setSoTimeout(instance.READ_DATA_TIMEOUT); // 设置建立连接超时时间
					params.setConnectionTimeout(instance.CONNECTION_TIMEOUT); // 设置建立连接超时时间
					params.setDefaultMaxConnectionsPerHost(max);
					// params.setParameter(HttpMethodParams.RETRY_HANDLER, new
					// DefaultHttpMethodRetryHandler());
					params.setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, CONTENT_CHARSET); // 设置编码

					httpClient = new HttpClient(connectionManager);
				}
			}
		}
		return httpClient;
	}

	/**
	 * 队列任务
	 * 
	 */
	public static class RequestCallable implements Callable<String> {
		/** url地址 */
		private String url;
		/** 请求方法 */
		private String method;
		/** 参数 */
		private Map<String, Object> paramMap;
		/** json参数 */
		private String postJson;

		public RequestCallable(String method, String url, Map<String, Object> paramMap, String postJson) {
			this.url = url;
			this.method = method;
			this.paramMap = paramMap;
			this.postJson = postJson;
		}

		public String call() throws Exception {
			String response = doRequest(method, url, paramMap, postJson);
			return response;
		}
	}

	// public static void main(String[] args) {
	// String doGet = doPost("http://www.baidu.com", new HashMap());
	// System.err.println(doGet);
	// }

	/**
	 * 处理请求
	 * 
	 * @param method
	 * @param url
	 * @param signName
	 * @param signKey
	 * @param paramMap
	 * @return
	 */
	@SuppressWarnings("deprecation")
	public static String doRequest(String method, String url, Map<String, Object> paramMap, String postJson) {
		HttpMethodBase httpMethod = null;
		if (HTTP_METHOD_GET.equalsIgnoreCase(method)) {
			httpMethod = new GetMethod(url);
			httpMethod.setRequestHeader("Content-Type", "text/plain; charset=\"utf-8\"");
		} else if (HTTP_METHOD_POST.equalsIgnoreCase(method)) {
			httpMethod = new PostMethod(url);
			httpMethod.setRequestHeader("Content-Type", "application/json; charset=\"utf-8\"");
		} else {
			throw new IllegalArgumentException(String.format("method不支持:%s", method));
		}
		// 产生签名
		// generateSign(method, signName, signKey, paramMap, false, false);
		// 设置cookie策略
		httpMethod.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
		// 设置User-Agent
		httpMethod.setRequestHeader("Cache-Control", "max-age=0");
		httpMethod.setRequestHeader("User-Agent", "http-client");
		// 使用系统提供的默认的恢复策略
		httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
		if (httpMethod instanceof PostMethod && StringUtils.isNotBlank(postJson)) {
			((PostMethod) httpMethod).setRequestBody(postJson);
		} else if (paramMap != null) {
			byte i = 0;
			NameValuePair[] queryParams = new NameValuePair[paramMap.size()];
			for (Entry<String, Object> entry : paramMap.entrySet()) {
				queryParams[i++] = new NameValuePair(entry.getKey(), entry.getValue().toString());
			}
			if (httpMethod instanceof PostMethod) {
				((PostMethod) httpMethod).setRequestBody(queryParams);
			} else {
				httpMethod.setQueryString(queryParams);
			}
		}
		String response = StringUtils.EMPTY;
		// http请求
		HttpClient httpClient = getHttpClient();
		try {
			HttpConnectionManagerParams connectionParams = httpClient.getHttpConnectionManager().getParams();
			connectionParams.setSoTimeout(instance.READ_DATA_TIMEOUT); // 设置建立连接超时时间
			connectionParams.setConnectionTimeout(instance.CONNECTION_TIMEOUT); // 设置建立连接超时时间
			httpClient.executeMethod(httpMethod);
			String body = new String(httpMethod.getResponseBodyAsString().getBytes("UTF-8"));
			if (httpMethod.getStatusCode() == HttpStatus.SC_OK) {
				response = body;
			}
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("请求地址:{} 返回:{}", httpMethod.getURI(), body);
			}
		} catch (Exception e) {
			LOGGER.error("http请求异常,url:{} 参数:{}", url, paramMap);
			LOGGER.error("", e);
		} finally {
			if (httpMethod != null) {
				try {
					httpMethod.releaseConnection();
				} catch (Exception e) {
					LOGGER.error("释放HTTP连接:{}", e);
				}
			}
		}
		return response;
	}

	/**
	 * 处理请求
	 * 
	 * @param method
	 * @param url
	 * @param signName
	 * @param signKey
	 * @param paramMap
	 * @return
	 */
	@SuppressWarnings("deprecation")
	public static String doRequest(String method, String url, Map<String, Object> paramHeaderMap,
			Map<String, Object> paramBodyMap, String postJson) {
		HttpMethodBase httpMethod = null;
		if (HTTP_METHOD_GET.equalsIgnoreCase(method)) {
			httpMethod = new GetMethod(url);
			httpMethod.setRequestHeader("Content-Type", "text/plain; charset=\"utf-8\"");
		} else if (HTTP_METHOD_POST.equalsIgnoreCase(method)) {
			httpMethod = new PostMethod(url);
			httpMethod.setRequestHeader("Content-Type", "application/json; charset=\"utf-8\"");
		} else {
			throw new IllegalArgumentException(String.format("method不支持:%s", method));
		}
		// 产生签名
		// generateSign(method, signName, signKey, paramMap, false, false);
		// 设置cookie策略
		httpMethod.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
		// 设置User-Agent
		httpMethod.setRequestHeader("Cache-Control", "max-age=0");
		httpMethod.setRequestHeader("User-Agent", "http-client");
		if (paramHeaderMap != null) {
			for (String key : paramHeaderMap.keySet()) {
				httpMethod.setRequestHeader(key, paramHeaderMap.get(key).toString());
			}

		}
		// 使用系统提供的默认的恢复策略
		httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
		if (httpMethod instanceof PostMethod && StringUtils.isNotBlank(postJson)) {
			((PostMethod) httpMethod).setRequestBody(postJson);
		} else if (paramBodyMap != null) {
			byte i = 0;
			NameValuePair[] queryParams = new NameValuePair[paramBodyMap.size()];
			for (Entry<String, Object> entry : paramBodyMap.entrySet()) {
				queryParams[i++] = new NameValuePair(entry.getKey(), entry.getValue().toString());
			}
			if (httpMethod instanceof PostMethod) {
				((PostMethod) httpMethod).setRequestBody(queryParams);
			} else {
				httpMethod.setQueryString(queryParams);
			}
		}
		String response = StringUtils.EMPTY;
		// http请求
		HttpClient httpClient = getHttpClient();
		try {
			HttpConnectionManagerParams connectionParams = httpClient.getHttpConnectionManager().getParams();
			connectionParams.setSoTimeout(instance.READ_DATA_TIMEOUT); // 设置建立连接超时时间
			connectionParams.setConnectionTimeout(instance.CONNECTION_TIMEOUT); // 设置建立连接超时时间
			httpClient.executeMethod(httpMethod);
			String body = new String(httpMethod.getResponseBodyAsString().getBytes("UTF-8"));
			if (httpMethod.getStatusCode() == HttpStatus.SC_OK) {
				response = body;
			}
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("请求地址:{} 返回:{}", httpMethod.getURI(), body);
			}
		} catch (Exception e) {
			LOGGER.error("http请求异常{},url:{} 参数:{}",e.getClass().getName(), url, paramBodyMap);
		} finally {
			if (httpMethod != null) {
				try {
					httpMethod.releaseConnection();
				} catch (Exception e) {
					LOGGER.error("释放HTTP连接:{}", e);
				}
			}
		}
		return response;
	}

	// /**
	// * 产生签名
	// *
	// * @param method
	// * @param signName
	// * @param signKey
	// * @param params
	// * @param signParams
	// * @return
	// */
	// public static String generateSign(String method, String signName, String
	// signKey, Map<String, Object> params,
	// boolean containKey, boolean urlEncodeValue) {
	// String sign = StringUtils.EMPTY;
	// if (params != null && !params.isEmpty() && StringUtils.isNotBlank(signName))
	// {
	// params.remove(signName);
	// StringBuilder sb = new StringBuilder();
	// List<String> keys = new ArrayList<String>(params.keySet());
	// Collections.sort(keys);
	// for (String key : keys) {
	// if (containKey) {
	// sb.append(key);
	// }
	// String value = StringUtils.defaultString(params.get(key).toString());
	// if (urlEncodeValue) {
	// try {
	// value = URLEncoder.encode(value, CONTENT_CHARSET);
	// } catch (UnsupportedEncodingException e) {
	// e.printStackTrace();
	// }
	// }
	// sb.append(value);
	// }
	// sb.append(signKey);
	// sign = CryptUtils.md5(sb.toString());
	// params.put(signName, sign);
	// }
	// return sign;
	// }

	/**
	 * 异步http请求
	 * 
	 * @param method
	 *            请求方式
	 * @param url
	 *            请求地址
	 * @param paramMap
	 *            参数集合
	 * @param object
	 *            json对象
	 * @param waitSecs
	 *            等待返回时间
	 * @return {@link ResultObject} 返回值对象
	 */
	public static String asyncHttpRequest(String method, String url, Map<String, Object> paramMap, Object object,
			int waitSecs) {
		if (StringUtils.isBlank(url)) {
			return StringUtils.EMPTY;
		}
		String postJson = JsonUtils.object2String(object);
		Future<String> future = submit(new RequestCallable(method, url, paramMap, postJson));
		String response = StringUtils.EMPTY;
		if (waitSecs > 0) {
			try {
				response = future.get(waitSecs, TimeUnit.SECONDS);
			} catch (TimeoutException ex) {
				LOGGER.error("请求url:{}, params:{}时超时", url, paramMap);
			} catch (Exception ex) {
				LOGGER.error("请求url:{}, params:{}时报错", url, paramMap);
				LOGGER.error("", ex);
			}
		}
		return response;
	}

	public static String doGet(String url) {
		String response = doRequest(HTTP_METHOD_GET, url, null, null);
		return response;
	}

	public static String asyncGet(String url) {
		String response = asyncHttpRequest(HTTP_METHOD_GET, url, null, null, 0);
		return response;
	}

	public static String doPost(String url, Map<String, Object> paramHeaderMap, Map<String, Object> paramBodyMap) {
		String response = doRequest(HTTP_METHOD_POST, url, paramHeaderMap, paramBodyMap, null);
		return response;
	}

	public static String doPost(String url, Map<String, Object> paramHeaderMap, String postJson) {
		String response = doRequest(HTTP_METHOD_POST, url, paramHeaderMap, null, postJson);
		return response;
	}

	public static String doPost(String url, Object object) {
		String postJson = JsonUtils.object2String(object);
		String response = doRequest(HTTP_METHOD_POST, url, null, postJson);
		return response;
	}

	public static String asyncPost(String url, Object object) {
		String response = asyncHttpRequest(HTTP_METHOD_POST, url, null, object, 0);
		return response;
	}

	public static void main(String... args) {
		// String reponse = doRequest("GET", "http://103.19.96.232/test.php", "", "",
		// null);
		// System.err.println(reponse);
		int count = 1;
		long start = System.currentTimeMillis();
		String str = "";
		final CountDownLatch downLatch = new CountDownLatch(count);
		for (int i = 0; i < count; i++) {
			ExecutorUtils.submit(new Runnable() {

				public void run() {

					try {
						System.err.println(doRequest(HTTP_METHOD_GET, "https://www.baidu.com", null, null));
					} finally {
						downLatch.countDown();
					}

				}
			});
		}
		// System.err.println(str);
		try {
			downLatch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.err.println(String.format("数量:%d 耗时:%d", count, (System.currentTimeMillis() - start)));
		System.exit(0);
	}

	public void setConnectionTimeout(int connectionTimeout) {
		CONNECTION_TIMEOUT = connectionTimeout;
	}

	public int setReadDataTimeout() {
		return READ_DATA_TIMEOUT;
	}

	public void getConnectionTimeout(int connectionTimeout) {
		CONNECTION_TIMEOUT = connectionTimeout;
	}

	public int getReadDataTimeout() {
		return READ_DATA_TIMEOUT;
	}

}
